package redis

import (
	"flag"
	"fmt"
	"strings"

	"github.com/go-redis/redis"
)

var (
	srcDB, targetDB             int
	srcClient, targetClient     redis.Cmdable
	srcAddress, targetAddress   string
	srcPassword, targetPassword string
	srcKeys                     string
)

func init() {
	flag.StringVar(&srcAddress, "s", "127.0.0.1:6379", "source redis address")
	flag.StringVar(&targetAddress, "t", "127.0.0.1:6379", "target redis address")
	flag.StringVar(&srcKeys, "keys", "", "keys,  more ','")
	flag.IntVar(&srcDB, "sdb", 0, "source redis db")
	flag.IntVar(&targetDB, "tdb", 0, "target redis db")
	flag.StringVar(&srcPassword, "sa", "", "source redis password")
	flag.StringVar(&targetPassword, "ta", "", "target redis password")
	flag.Parse()

	srcClient = redis.NewClient(&redis.Options{
		Addr:     srcAddress,
		Password: srcPassword,
		DB:       srcDB,
	})

	if err := srcClient.Ping().Err(); err != nil {
		panic(fmt.Errorf("address: %s, error: %v", srcAddress, err))
	}

	targetClient = redis.NewClient(&redis.Options{
		Addr:     targetAddress,
		Password: targetPassword,
		DB:       targetDB,
	})

	if err := targetClient.Ping().Err(); err != nil {
		panic(fmt.Errorf("address: %s, error: %v", targetAddress, err))
	}

	if len(srcKeys) == 0 {
		panic("keys is empty")
	}
}

func main() {
	keys := strings.Split(srcKeys, ",")
	for _, key := range keys {
		var err error

		targetClient.Del(key)
		sType := srcClient.Type(key).Val()
		switch sType {
		case "string":
			err = targetClient.Set(key, srcClient.Get(key).Val(), srcClient.TTL(key).Val()).Err()
		case "hash":
			values := make(map[string]interface{})
			for k, v := range srcClient.HGetAll(key).Val() {
				values[k] = v
			}
			err = targetClient.HMSet(key, values).Err()
		case "set":
			values := make([]interface{}, 0)
			for _, v := range srcClient.SMembers(key).Val() {
				values = append(values, v)
			}
			err = targetClient.SAdd(key, values...).Err()
		case "zset":
			values := make([]redis.Z, 0)
			for _, v := range srcClient.ZRangeWithScores(key, 0, srcClient.ZCard(key).Val()).Val() {
				values = append(values, v)
			}
			err = targetClient.ZAdd(key, values...).Err()
		case "list":
			values := make([]interface{}, 0)
			for _, v := range srcClient.LRange(key, 0, srcClient.LLen(key).Val()).Val() {
				values = append(values, v)
			}
			err = targetClient.LPush(key, values...).Err()
		default:
			err = fmt.Errorf("`%s` No processing", sType)
		}

		if err != nil {
			fmt.Println("key: ", key, "type: ", sType, "error: ", err.Error())
		} else {
			fmt.Println("key: ", key, "type: ", sType, "			-> ok")
		}
	}

	fmt.Println("done")
}
